{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Parte 8 bis - Introdução a Protocolos\n",
    "\n",
    "### Contexto\n",
    "\n",
    "Agora que passamos pelos planos, nós iremos introduzir um novo objeto chamado _Protocol_ (Protocolo). Um _Protocol_ coordena uma sequência da Planos, implementa-os em workers distantes e executa-os em uma passada só.\n",
    "\n",
    "O Protocolo é um objeto de alto nível que contém uma lógica de computações complexas distribuidas através de vários workers. A principal função de um _Protocol_ é a habilidade de ser enviado / procurado/ buscado de volta entre workers e finalmente distribuído para workers identificados. Então um usuário pode planejar um protocolo, carregá-lo para uma rede de workers, e qualquer outro worker será capaz de procurá-lo, baixá-lo e aplicar o programa de computação que ele contém em workers ao qual ele está conectado.\n",
    "\n",
    "Vamos ver como usá-lo!\n",
    "\n",
    "Autores:\n",
    "- Théo Ryffel - Twitter [@theoryffel](https://twitter.com/theoryffel) - GitHub: [@LaRiffle](https://github.com/LaRiffle)\n",
    "\n",
    "Tradutor:\n",
    "- João Lucas - GitHub: [@joaolcaas](https://github.com/joaolcaas) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Crie e Distribua"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Protocolos são criados fornecendo uma lista de pares `(worker, plan)`.  `worker` pode ser tanto um worker real quanto um id do worker ou uma _string_ que representa um worker fictício. Esse último caso pode ser usado na criação para especificar que dois planos devem ser pertencidos (ou não pertencidos) ao mesmo worker na implementação. `plan` pode ser tanto um Plano como um PointerPlan."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch as th\n",
    "import syft as sy\n",
    "hook = sy.TorchHook(th)\n",
    "\n",
    "# IMPORTANTE: Worker local não deve ser um worker cliente\n",
    "hook.local_worker.is_client_worker = False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Vamos definir 3 planos e alimentá-los para um protocolo. Todos eles implementam uma operação de incremento."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@sy.func2plan(args_shape=[(1,)])\n",
    "def inc1(x):\n",
    "    return x + 1\n",
    "\n",
    "@sy.func2plan(args_shape=[(1,)])\n",
    "def inc2(x):\n",
    "    return x + 1\n",
    "\n",
    "@sy.func2plan(args_shape=[(1,)])\n",
    "def inc3(x):\n",
    "    return x + 1\n",
    "\n",
    "protocol = sy.Protocol([(\"worker1\", inc1), (\"worker2\", inc2), (\"worker3\", inc3)])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Agora nós precisamos ligar o Protocolo aos workers, o que é feito chamando `.deploy(*workers)`. Vamos criar alguns workers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob = sy.VirtualWorker(hook, id=\"bob\")\n",
    "alice = sy.VirtualWorker(hook, id=\"alice\")\n",
    "charlie = sy.VirtualWorker(hook, id=\"charlie\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "workers = alice, bob, charlie\n",
    "\n",
    "protocol.deploy(*workers)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Você pode ver que os planos já foram enviados para os workers apropriados: isso já foi implantado!\n",
    "\n",
    "Esse processo tem sido feito em 2 fases: primeiramente, nós mapeamos os workers fictícios fornecidos na criação (nomeados por _strings_ ) para os workers fornecidos e, em segundo lugar, nós enviamos os planos correspondentes para cada um deles."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Executar um protocolo\n",
    "\n",
    "Executar um protocolo significa executar todos os planos sequencialmente. Para isso, você fornece alguma dado de entrada  que é enviado para a primeira localidade de um plano. Esse primeiro plano é executado e sua saída é redirecionada para a localização do segundo plano, e assim por diante. O resultado final é retornado depois que todos os planos foram executados, e é composto de apontadores para a última localização do plano."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = th.tensor([1.0])\n",
    "ptr = protocol.run(x)\n",
    "ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ptr.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Essa entrada 1.0 passou por 3 planos e foi incrementada 3 vezes, por isso agora ela é igual 4.0!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Na verdade, voce também pode **executar um protocolo remotamente** em alguns apontadores dos dados:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "james = sy.VirtualWorker(hook, id=\"james\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "protocol.send(james)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = th.tensor([1.0]).send(james)\n",
    "ptr = protocol.run(x)\n",
    "ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Como você pode ver, o resultado é um apontador para james."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ptr = ptr.get()\n",
    "ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ptr = ptr.get()\n",
    "ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Busca por um protocolo\n",
    "\n",
    "Em cenários reais você pode querer baixar um protocolo remoto, para distribuir em seus próprios _workers_ e executá-lo nos seus dados:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Vamos inicializar um protocolo **que não é distribuído**, e colocá-lo em um _worker_ remoto."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "protocol = sy.Protocol([(\"worker1\", inc1), (\"worker2\", inc2), (\"worker3\", inc3)])\n",
    "protocol.tag('my_protocol')\n",
    "protocol.send(james)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "me = sy.hook.local_worker # get access to me as a local worker"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Agora nós fazemos uma busca para encontrar o protocolo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "responses = me.request_search(['my_protocol'], location=james)\n",
    "responses"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Você tem acesso ao apontador para o Protocolo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ptr_protocol = responses[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Como um apontador normal, você pode pegar isso de volta:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "protocol_back = ptr_protocol.get()\n",
    "protocol_back"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "E nós podemos fazer como fizemos nas partes 1. & 2."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "protocol_back.deploy(alice, bob, charlie)\n",
    "\n",
    "x = th.tensor([1.0])\n",
    "ptr = protocol_back.run(x)\n",
    "ptr.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mais exemplos do mundo real virão com Protocolos, mas você já pode observar todas as possibilidades que foram abertas por esse novo objeto!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Dê-nos uma estrela em nosso repo do PySyft no GitHub\n",
    "\n",
    "A maneira mais fácil de ajudar nossa comunidade é adicionando uma estrela nos nossos repositórios! Isso ajuda a aumentar a conscientização sobre essas ferramentas legais que estamos construindo.\n",
    "\n",
    "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "### Veja nossos tutoriais no GitHub!\n",
    "\n",
    "Fizemos tutoriais muito bons para entender melhor como deve ser a Aprendizagem Federada e a proteção de Privacidade, e como estamos construindo as coisas básicas que precisamos para fazer com que isso aconteça.\n",
    "\n",
    "- [Tutoriais do PySyft](https://github.com/OpenMined/PySyft/tree/master/examples/tutorials)\n",
    "\n",
    "### Junte-se ao Slack!\n",
    "\n",
    "A melhor maneira de manter-se atualizado sobre os últimos avanços é se juntar à nossa comunidade! \n",
    "\n",
    "- [http://slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### Contribua com o projeto!\n",
    "\n",
    "A melhor maneira de contribuir para a nossa comunidade é se tornando um contribuidor do código! A qualquer momento, você pode acessar a página de *Issues* (problemas) do PySyft no GitHub e filtrar por \"Projetos\". Isso mostrará todas as etiquetas (tags) na parte superior, com uma visão geral de quais projetos você pode participar! Se você não deseja ingressar em um projeto, mas gostaria de codificar um pouco, também pode procurar mais mini-projetos \"independentes\" pesquisando problemas no GitHub marcados como \"good first issue\".\n",
    "\n",
    "- [Etiquetados como Good First Issue](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### Doar\n",
    "\n",
    "Se você não tem tempo para contribuir com nossa base de códigos, mas ainda deseja nos apoiar, também pode se tornar um Apoiador em nosso Open Collective. Todas as doações vão para hospedagem na web e outras despesas da comunidade, como hackathons e meetups!\n",
    "\n",
    "[Página do Open Collective do OpenMined](https://opencollective.com/openmined)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5rc1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
